package com.dctp.common.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Locale;

/**
 * 日期工具类（基于 java.time 封装）
 */
public final class DateUtil {

    // 默认时区（可根据需要修改）
    private static final ZoneId DEFAULT_ZONE = ZoneId.systemDefault();

    // 常用日期格式
    public static final String DATE_PATTERN = "yyyy-MM-dd";
    public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String TIME_PATTERN = "HH:mm:ss";
    public static final String ISO_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    private DateUtil() {
        // 禁止实例化
    }

    // ---------------------- 基础方法 ----------------------

    /**
     * 获取当前时间（默认时区）
     */
    public static LocalDateTime now() {
        return LocalDateTime.now(DEFAULT_ZONE);
    }

    /**
     * 获取当前时间戳（毫秒）
     */
    public static long currentTimestamp() {
        return System.currentTimeMillis();
    }

    public static long startDayTimestamp() {
        LocalDateTime localDateTime = startOfDay(LocalDateTime.now());
        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    // ---------------------- 格式化和解析 ----------------------

    /**
     * 日期转字符串（默认格式：yyyy-MM-dd HH:mm:ss）
     */
    public static String format(LocalDateTime dateTime) {
        return format(dateTime, DATE_TIME_PATTERN);
    }

    /**
     * 日期转字符串（自定义格式）
     */
    public static String format(LocalDateTime dateTime, String pattern) {
        return dateTime.format(DateTimeFormatter.ofPattern(pattern, Locale.getDefault()));
    }

    /**
     * 字符串转日期（默认格式：yyyy-MM-dd HH:mm:ss）
     */
    public static LocalDateTime parse(String dateStr) {
        return parse(dateStr, DATE_TIME_PATTERN);
    }

    /**
     * 字符串转日期（自定义格式）
     */
    public static LocalDateTime parse(String dateStr, String pattern) {
        return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
    }

    // ---------------------- 日期转换 ----------------------

    /**
     * Date 转 LocalDateTime（默认时区）
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return date.toInstant().atZone(DEFAULT_ZONE).toLocalDateTime();
    }

    /**
     * LocalDateTime 转 Date（默认时区）
     */
    public static Date toDate(LocalDateTime dateTime) {
        return Date.from(dateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    /**
     * 时间戳转 LocalDateTime（默认时区）
     */
    public static LocalDateTime fromTimestamp(long timestamp) {
        return Instant.ofEpochMilli(timestamp).atZone(DEFAULT_ZONE).toLocalDateTime();
    }

    // ---------------------- 日期计算 ----------------------

    /**
     * 日期加减天数
     */
    public static LocalDateTime plusDays(LocalDateTime dateTime, long days) {
        return dateTime.plusDays(days);
    }

    /**
     * 日期加减小时
     */
    public static LocalDateTime plusHours(LocalDateTime dateTime, long hours) {
        return dateTime.plusHours(hours);
    }

    /**
     * 日期加减月数
     */
    public static LocalDateTime plusMonths(LocalDateTime dateTime, int months) {
        return dateTime.plusMonths(months);
    }

    // ---------------------- 日期比较 ----------------------

    /**
     * 判断是否在日期范围内（包含边界）
     */
    public static boolean isBetween(LocalDateTime date, LocalDateTime start, LocalDateTime end) {
        return !date.isBefore(start) && !date.isAfter(end);
    }

    /**
     * 计算两个日期之间的天数差
     */
    public static long daysBetween(LocalDateTime start, LocalDateTime end) {
        return Duration.between(start, end).toDays();
    }

    // ---------------------- 特殊时间点获取 ----------------------

    /**
     * 获取当天的开始时间（00:00:00）
     */
    public static LocalDateTime startOfDay(LocalDateTime dateTime) {
        return dateTime.toLocalDate().atStartOfDay();
    }

    /**
     * 获取当天的结束时间（23:59:59）
     */
    public static LocalDateTime endOfDay(LocalDateTime dateTime) {
        return dateTime.toLocalDate().atTime(23, 59, 59);
    }

    /**
     * 获取本月的第一天
     */
    public static LocalDateTime firstDayOfMonth() {
        return LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth());
    }

    // ---------------------- 时区处理 ----------------------

    /**
     * 转换时区（例如：UTC → Asia/Shanghai）
     */
    public static LocalDateTime convertZone(LocalDateTime dateTime, ZoneId fromZone, ZoneId toZone) {
        return dateTime.atZone(fromZone).withZoneSameInstant(toZone).toLocalDateTime();
    }

    /**
     * 转换为 ISO 格式字符串（UTC 时区）
     */
    public static String toIsoString(LocalDateTime dateTime) {
        return dateTime.atZone(DEFAULT_ZONE)
                .withZoneSameInstant(ZoneOffset.UTC)
                .format(DateTimeFormatter.ofPattern(ISO_PATTERN));
    }

    /**
     * 将LocalDateTime转换为毫秒时间戳（基于指定时区）
     * @param dateTime 本地日期时间
     * @param zoneId   时区（如 ZoneId.of("Asia/Shanghai")）
     * @return 毫秒时间戳（自1970-01-01T00:00:00Z的毫秒数）
     */
    public static long toEpochMilli(LocalDateTime dateTime, ZoneId zoneId) {
        return dateTime.atZone(zoneId).toInstant().toEpochMilli();
    }

    /**
     * 使用默认时区转换
     */
    public static long toEpochMilli(LocalDateTime dateTime) {
        return toEpochMilli(dateTime, ZoneId.systemDefault());
    }

    
    /**
     * 将时间戳（秒或毫秒）转为LocalDateTime
     * @param timestamp 时间戳（秒或毫秒）
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(long timestamp) {
        if (String.valueOf(timestamp).length() == 13) {
            // 毫秒
            return Instant.ofEpochMilli(timestamp)
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
        } else {
            // 秒
            return Instant.ofEpochSecond(timestamp)
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
        }
    }

    /**
     * ✅ 获取当天结束时间的 Unix 时间戳（秒）
     */
    public static long endOfTodayEpoch() {
        LocalDate today = LocalDate.now();
        LocalDateTime endOfDay = today.atTime(LocalTime.MAX); // 23:59:59.999999999
        return endOfDay.toEpochSecond(ZoneOffset.UTC); // 取秒级别
    }

    /**
     * ✅ 获取当天剩余秒数（适合 setex 用）
     */
    public static long getSecondsToEndOfDay() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
        return ChronoUnit.SECONDS.between(now, endOfDay);
    }

    public static void main(String[] args) {
        System.out.println(ZoneId.systemDefault());
    }
}